# Created by Gerikes for Planetfall
# Search all the scheme files in the XML directory for changes from the default.
# Any new tags it finds, it captures and, hoping there is documentation, documents.
# Then, will take all of these and put them into a wiki format.

import re, os, shutil

strModName = "Planetfall"
strXMLFolder = os.path.join("..","Planetfall","Assets","XML")

reSchemaFile = re.compile('[\w]*Schema[A-Za-z]*\.xml')
reElementName = re.compile('''\s*<element type="([a-zA-Z0-9]+)"''')
reElementListStartName = re.compile('''\s*<ElementType name="([a-zA-Z0-9]+)".*content="eltOnly"''')
reElementListEnd = re.compile('\s*</ElementType>')
rePlanetfallBegin = re.compile(".*Added for Planetfall.*")
rePlanetfallEnd = re.compile(".*End Added for Planetfall.*")
rePlanetfallComment = re.compile(".*\<!--(.*)-->.*")

pSchemaSkipFilenames = ['..\\Planetfall\\Assets\\XML\\CIV4GlobalDefinesSchema.xml']

class Element:
    def __init__(self):
        self.strElementName = ""
        self.pTags = []
        self.bIsPlanetfall = False
        self.strComment = "[SEP]No Comment"

# Walk through all the XML files, looking for a schema
def getSchemaFilenames():
    pSchemaFilenames = []
    for strRoot, pDirs, pFiles in os.walk(strXMLFolder):
        for strFilename in pFiles:
            pMatch = reSchemaFile.search(strFilename)
            if pMatch != None:
                pSchemaFilenames.append(os.path.join(strRoot, strFilename))
        if '.svn' in pDirs:
            pDirs.remove('.svn')  # don't visit CVS directories

    # Skip these
    for strSkipMe in pSchemaSkipFilenames:
        if strSkipMe in pSchemaFilenames:
            pSchemaFilenames.remove(strSkipMe)
    return pSchemaFilenames

def getNodesFromFile(strFilename):
    pNodes = {}
    bIsPlanetfall = False
    strCurrentElement = ""
    pFile = open(strFilename, "r")
    for strLine in pFile.readlines():
        if bIsPlanetfall:
            if rePlanetfallEnd.match(strLine) <> None:
                bIsPlanetfall = False
        else:
            if rePlanetfallBegin.match(strLine) <> None:
                bIsPlanetfall = True

        pElementNameMatch = reElementName.match(strLine)
        if pElementNameMatch <> None:
            strNewTag = pElementNameMatch.groups()[0]
            pLeaf = Element()
            pLeaf.strElementName = strNewTag
            pLeaf.bIsPlanetfall = bIsPlanetfall
            pCommentMatch = rePlanetfallComment.match(strLine)
            if pCommentMatch <> None:
                pLeaf.strComment = "[SEP]%s" % pCommentMatch.groups()[0]
            
            
            pNodes[strCurrentElement].pTags.append(pLeaf)
            continue

        pElementListStartNameMatch =  reElementListStartName.match(strLine)
        if pElementListStartNameMatch <> None:
            strCurrentElement = pElementListStartNameMatch.groups()[0]
            pElement = Element()
            pElement.strElementName = strCurrentElement
            pElement.bIsPlanetfall = bIsPlanetfall
            pCommentMatch = rePlanetfallComment.match(strLine)
            if pCommentMatch <> None:
                pLeaf.strComment = "[SEP]%s" % pCommentMatch.groups()[0]
            pNodes[strCurrentElement] = pElement
            continue

        pElementListEndMatch = reElementListEnd.match(strLine)
        if pElementListEndMatch <> None:
            strCurrentElement = ""

    if pNodes.has_key(""):
        print "Warning: Recieved blank key in file %s!" % strFilename

    pFile.close()



    return pNodes

def getRootNodes(pNodes):
    pRootNodes = []

    # Make every node a root node.
    for pNode in pNodes.values():
        pRootNodes.append(pNode.strElementName)

    # Now, remove from that list the ones who we find to be elements of others.
    for pNode in pNodes.values():
        for pChildNode in pNode.pTags:
            if pChildNode.strElementName in pRootNodes:
                pRootNodes.remove(pChildNode.strElementName)

    return pRootNodes

def isLeaf(strElement, pNodesDict):
    return not pNodesDict.has_key(strElement)

def getTagsFromTree(strRoot, pNodesDict, strPrepend):
    pReturnTags = []

    for pNodes in pNodesDict[strRoot].pTags:
        if isLeaf(pNodes.strElementName, pNodesDict):
            if pNodes.bIsPlanetfall:
                pReturnTags.append("%s%s/%s %s" % (strPrepend, strRoot, pNodes.strElementName, pNodes.strComment))
        else:
            pTags = getTagsFromTree(pNodes.strElementName, pNodesDict, "%s%s/" % (strPrepend, strRoot))
            pReturnTags.extend(pTags)

    #if len(pReturnTags) > 0:
    #    pReturnTags = ["%s%s %s" % (strPrepend, strRoot, pNodesDict[strRoot].strComment)] + pReturnTags
    return pReturnTags    

# Returns a tuple, with Directory name (0) and a dictionary of filenames -> tag lists
def convertTagsToDirectoryDictionary(strSchemaFilename, pTags):
    strDir = strSchemaFilename.split("XML\\")[1].split("\\")[0]
    pFilenameTags = {}

    pDict = {}
    for strTag in pTags:
        strFilename = strTag.split("/")[0] + ".xml"
        strElement = strTag.split("/")[1:]

        if not pDict.has_key(strFilename):
            pDict[strFilename] = []

        pDict[strFilename].append(strElement)
            
    return pDict

WIKI_FILE_TEMPLATE = \
"""#summary All the Planetfall tags that are used $XML_FILENAME

[XMLTagsByFile  XML]

---->[XMLTagsByFile$DIRECTORY $DIRECTORY]

----------->!$XML_FILENAME

= $XML_FILENAME =

$BODY
"""

WIKI_TAGS_TEMPLATE = \
"""== $TAG_SECTION ==

$TAG_HEADER
$TAGS


"""

def getLinklessTag(strTag):
    if strTag[0].isupper():
        for i in range(1, len(strTag)):
            if strTag[i].upper():
                return "!%s" % strTag

    return strTag

def getWikTagSection(strSectionName, pSectionTags):
    strSource = WIKI_TAGS_TEMPLATE
    strSource = strSource.replace("$TAG_SECTION", strSectionName)

    iLongestTagDepth = 0
    for pTag in pSectionTags:
        if len(pTag) > iLongestTagDepth:
            iLongestTagDepth = len(pTag)

    strHeader = "||"
    for i in range(0, iLongestTagDepth + 2):
        if i == 0:
            strHeader += "Elements||"
        elif i == iLongestTagDepth + 1:
            strHeader += "Comment||"
        else:
            strHeader += " ||"

    strSource = strSource.replace("$TAG_HEADER", strHeader)

    strTags = ""
    for pTag in pSectionTags:
        pNewTag = pTag[0:-1]
        pNewTag.append(pTag[-1].split("[SEP]")[0])
        pNewTag.append(pTag[-1].split("[SEP]")[1])
        
        strTags += "||"
        for i in range(0, iLongestTagDepth + 1):
            if i > len(pNewTag) - 2:
                strTags += " ||"
            else:
                strTags += "%s||" % getLinklessTag(pNewTag[i])

        strTags += "%s||" % pNewTag[-1] # Comment
        strTags += "\n"
    strSource = strSource.replace("$TAGS", strTags)


    return strSource

def convertFileTagsToWiki(strDirectory, strFilename, pTags):
    strWikiSource = WIKI_FILE_TEMPLATE
    strWikiSource = strWikiSource.replace("$DIRECTORY", strDirectory)
    strWikiSource = strWikiSource.replace("$XML_FILENAME", strFilename)

    iGetLongestTagDepth = 0
    pSectionDict = {}
    for pTag in pTags:
        if not pSectionDict.has_key(pTag[0]):
            pSectionDict[pTag[0]] = []
        pSectionDict[pTag[0]].append(pTag[1:])

    strBody = ""
    for strSection in pSectionDict.keys():
        strBody += getWikTagSection(strSection, pSectionDict[strSection])
        
    strWikiSource = strWikiSource.replace("$BODY", strBody)
    

    return strWikiSource

WIKI_MAIN_TEMPLATE = \
"""#summary All the files that have added tags for Planetfall.

= Introduction =

Whenever new tags are added, they must be placed into the schema file. By using a certain notation for adding comments in the schema file, I've created a script to take out those comments and make them into a wiki page for easy reference.

The following files have new XML tags:


== Files ==

$BODY
"""

def createWikiMain(pDirDict):
    strSource = WIKI_MAIN_TEMPLATE

    strBody = ""
    for strDir in pDirDict:
        strBody += " * [XMLTagsByFile%s %s]\n" % (strDir, strDir)
        for strFile in pDirDict[strDir]:
            print strFile
            strBody += "   * [%s %s]\n" % (strFile.split(".")[0] + "XMLTags", strFile)


    strSource = strSource.replace("$BODY", strBody)

    return strSource

WIKI_DIR_TEMPLATE = \
"""#summary All the Planetfall tags that are used the $DIR directory

[XMLTagsByFile  XML]

---->$DIR

= $DIR Directory =

"""

def createDirWiki(strDir, pDirDict):
    strSource = WIKI_DIR_TEMPLATE
    strSource = strSource.replace("$DIR", strDir)
    for strFile in pDirDict[strDir]:
        strSource += " * [%s %s]\n" % (strFile.split(".")[0] + "XMLTags", strFile)
    
    return strSource
    

if __name__ == "__main__":
    pDirDict = {}
    for strSchemaFilename in getSchemaFilenames():
        strDirectory = strSchemaFilename
        strDirectoryShort = strDirectory.split("XML")[1].split("\\")[1]
        pDirDict[strDirectoryShort] = []
        pNodesDict = getNodesFromFile(strSchemaFilename)
        pRootNodes = getRootNodes(pNodesDict)

        for strRoot in pRootNodes:
            pTags = getTagsFromTree(strRoot, pNodesDict, '')
            if len(pTags) > 0:
                pFileTags = convertTagsToDirectoryDictionary(strSchemaFilename, pTags)
                for strFile in pFileTags:
                    pDirDict[strDirectoryShort].append(strFile)
                    strSource = convertFileTagsToWiki(strDirectoryShort, strFile, pFileTags[strFile])
                    f = open("wiki/" + strFile.split(".")[0] + "XMLTags.wiki", "w")
                    f.write(strSource)
                    f.close()

        

    for strDir in pDirDict.keys():
        if len(pDirDict[strDir]) > 0:
            strSource = createDirWiki(strDir, pDirDict)
            f = open ("wiki/XMLTagsByFile%s.wiki" % strDir, "w")
            f.write(strSource)
            f.close()
        

    strSource = createWikiMain(pDirDict)
    f = open("wiki/XMLTagsByFile.wiki", "w")
    f.write(strSource)
    f.close()

    print "Finished script. Hit any key to exit."
    t = raw_input()
